﻿namespace NTLib.Core.UTest.Component
{
    using Exceptions.Component;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using NTLib.Core.Attributes;
    using NTLib.Core.Component;
    using NTLib.Core.Factories;
    using NTLib.Core.Pool;
    using NTLib.Core.Reflection;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    [TestClass]
    public class ComponentFactoryUTest
    {
        #region Neated

        [GuidAttribute("87da5a89-4380-48a3-b871-aa0a88472674")]
        class SimpleObj : IComponent
        {
            public Guid Id { get; set; }
        }

        [GuidAttribute("b1bd6272-5594-435b-a90d-6658391bc5fa")]
        [ConcurrentComponent]
        class Concurrent : SimpleObj
        {
        }

        [GuidAttribute("8a9e79f4-0463-44df-8920-02589fc03d96")]
        class PoolComponent : PoolItem, IComponent
        {
            public readonly Guid idPersist = Guid.NewGuid();
            public Guid Id { get; set; }

            protected override void OnReset()
            {
                Id = Guid.NewGuid();
            }
        }

        [GuidAttribute("df0d0de1-28c6-43de-91c7-d81e9bd991af")]
        [ConcurrentComponent]
        class PoolConcurrentComponent : PoolComponent
        {
        }

        #endregion

        #region Methods

        [TestCategory("Core.Component")]
        [TestMethod]
        public void ComponentFactory_Register()
        {
            ComponentFactory<IComponent> component = new ComponentFactory<IComponent>();

            try
            {
                component.Create(Guid.NewGuid());
            }
            catch (ComponentNotRegisteredException)
            {

            }

            component.Register<SimpleObj>();

            component.Create(typeof(SimpleObj).GetMandatoryAttribute<GuidAttribute>().Value);
        }


        [TestCategory("Core.Component")]
        [TestMethod]
        public void ComponentFactory_CreateConcurrent()
        {
            ComponentFactory<IComponent> fact = new ComponentFactory<IComponent>();
            Guid concurrent = typeof(Concurrent).GetMandatoryAttribute<GuidAttribute>().Value;
            Guid simpleObj = typeof(SimpleObj).GetMandatoryAttribute<GuidAttribute>().Value;

            fact.Register<Concurrent>();
            fact.Register<SimpleObj>();

            var c = fact.Create(concurrent);
            Assert.IsInstanceOfType(c, typeof(Concurrent));
            ((Concurrent)c).Id = concurrent;

            var c2 = fact.Create(concurrent);
            Assert.IsInstanceOfType(c2, typeof(Concurrent));

            Assert.AreEqual(c2.Id, c.Id);
        }

        [TestCategory("Core.Component")]
        [TestMethod]
        public void ComponentFactory_CreatePool()
        {
            ComponentFactory<IComponent> fact = new ComponentFactory<IComponent>();
            Guid pool = typeof(PoolComponent).GetMandatoryAttribute<GuidAttribute>().Value;
            Guid concurrent = typeof(Concurrent).GetMandatoryAttribute<GuidAttribute>().Value;
            Guid simpleObj = typeof(SimpleObj).GetMandatoryAttribute<GuidAttribute>().Value;

            fact.Register<PoolComponent>();
            fact.Register<Concurrent>();
            fact.Register<SimpleObj>();

            var c = fact.Create(pool);
            Guid persistant = ((PoolComponent)c).idPersist;
            ((PoolComponent)c).Dispose();

            var c2 = fact.Create(pool);
            Assert.AreEqual(persistant, (((PoolComponent)c2).idPersist));
        }


        [TestCategory("Core.Component")]
        [TestMethod]
        public void ComponentFactory_CreatePoolAndConcurrent()
        {
            ComponentFactory<IComponent> fact = new ComponentFactory<IComponent>();
            Guid pool = typeof(PoolComponent).GetMandatoryAttribute<GuidAttribute>().Value;
            Guid poolConcurrent = typeof(PoolConcurrentComponent).GetMandatoryAttribute<GuidAttribute>().Value;
            Guid concurrent = typeof(Concurrent).GetMandatoryAttribute<GuidAttribute>().Value;
            Guid simpleObj = typeof(SimpleObj).GetMandatoryAttribute<GuidAttribute>().Value;

            fact.Register<PoolComponent>();
            fact.Register<PoolConcurrentComponent>();
            fact.Register<Concurrent>();
            fact.Register<SimpleObj>();

            var c = fact.Create(poolConcurrent);
            Guid persistant = ((PoolConcurrentComponent)c).idPersist;

            var c2 = fact.Create(poolConcurrent);
            Assert.AreEqual(persistant, (((PoolConcurrentComponent)c2).idPersist));
        }

        #endregion
    }
}
